package com.mebs.model;

import org.jt.jet.JetUser;
import org.jt.jet.content.JetNamedObject;
import org.jt.jet.util.JetUtils;
import org.jt.jet.util.JetSecurityUtils;
import org.jt.jet.annotation.Field;
import org.jt.jet.annotation.ArgumentType;

import javax.persistence.*;
import java.util.*;

/**
 * User: sar
 */
@Entity()
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "USER")
@PrimaryKeyJoinColumn(name = "UserId")
public class User extends Occupier implements JetUser, JetNamedObject {

    public static final String NAME_ADMIN = "admin";

    @Column(name = "FirstName", length = 127, nullable = true)
    private String firstName;

    @Column(name = "LastName", length = 127, nullable = true)
    private String lastName;

    @Column(name = "MiddleName", length = 127, nullable = true)
    private String middleName;

    @Column(name = "Name", length = 64, unique = true, nullable = false)
    private String name;

    @Column(name = "Password", length = 64, nullable = false)
    private String passwordHash;

    @Column(name = "Email", length = 250, unique = true, nullable = false)
    @Field(optional = false)
    private String email;

    @ManyToOne(optional = true)
    @JoinColumn(name = "MainAddressId")
    private Address mainAddress;

    @ManyToOne(optional = true)
    @JoinColumn(name = "WorkAddressId")
    private Address workAddress;

    @ManyToOne(optional = true)
    @JoinColumn(name = "HomeAddressId")
    private Address homeAddress;

    @Column(name = "Status", nullable = false)
    private Integer status;

    @Column(name = "CreationTime", nullable = false)
    private Date creationTime;

    @ManyToOne(optional = true, fetch = FetchType.LAZY)
    @JoinColumn(name = "CreatedBy")
    @Field(type = ArgumentType.INSTANCE)
    private User createdBy;

    @Column(name = "LastLoginTime", nullable = true)
    private Date lastLoginTime;

    @ManyToOne(optional = false)
    @JoinColumn(name = "CompanyId")
    private Company company;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "USER_ROLE", joinColumns = {@JoinColumn(name = "UserId")},
        inverseJoinColumns = {@JoinColumn(name = "RoleId")})
    @Field(type = ArgumentType.INSTANCE)
    private java.util.Set<Role> roles;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "USER_ADDRESS_CURRENT", joinColumns = {@JoinColumn(name = "UserId")},
        inverseJoinColumns = {@JoinColumn(name = "AddressId")})
    @Field(type = ArgumentType.INSTANCE)
    private java.util.Set<Address> currentAddresses;


    /**
     * ********************** Getters-setters ***********************
     */
    public String getFirstName()
    {
        return firstName == null ? "" : firstName;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName == null ? "" : lastName;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public String getMiddleName()
    {
        return middleName == null ? "" : middleName;
    }

    public void setMiddleName(String middleName)
    {
        this.middleName = middleName;
    }

    public String getName()
    {
        return name == null ? "" : name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    String getPasswordHash()
    {
        return passwordHash;
    }

    void setPasswordHash(String passwordHash)
    {
        this.passwordHash = passwordHash;
    }

    public void setPassword(String password)
    {
        this.setPasswordHash(JetSecurityUtils.makeDigest(this.name, password));
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    public Integer getStatus()
    {
        return status;
    }

    public void setStatus(Integer status)
    {
        this.status = status;
    }

    public void setStatus(User.Status status)
    {
        this.status = status.status;
    }

    @Transient
    public boolean isDeleted()
    {
        return (this.status == User.Status.deleted.status);
    }

    @Transient
    public boolean isInactive()
    {
        return (this.status == User.Status.inactive.status);
    }

    public Address getMainAddress()
    {
        return mainAddress;
    }

    public void setMainAddress(Address mainAddress)
    {
        this.mainAddress = mainAddress;
    }

    public Address getWorkAddress()
    {
        return workAddress;
    }

    public void setWorkAddress(Address workAddress)
    {
        this.workAddress = workAddress;
    }

    @Transient
    public boolean hasWorkAddress(Address workAddress)
    {
        return this.workAddress != null &&
            workAddress != null &&
            this.workAddress.equals(workAddress);
    }

    public Address getHomeAddress()
    {
        return homeAddress;
    }

    public void setHomeAddress(Address homeAddress)
    {
        this.homeAddress = homeAddress;
    }

    @Transient
    public boolean hasHomeAddress(Address homeAddress)
    {
        return this.homeAddress != null &&
            homeAddress != null &&
            this.homeAddress.equals(homeAddress);
    }

    public Date getCreationTime()
    {
        return creationTime;
    }

    public void setCreationTime(Date creationTime)
    {
        this.creationTime = creationTime;
    }

    public User getCreatedBy()
    {
        return createdBy;
    }

    public void setCreatedBy(User createdBy)
    {
        this.createdBy = createdBy;
    }

    public Date getLastLoginTime()
    {
        return lastLoginTime;
    }

    public void setLastLoginTime(Date lastLoginTime)
    {
        this.lastLoginTime = lastLoginTime;
    }

    public Company getCompany()
    {
        return company;
    }

    public void setCompany(Company company)
    {
        this.company = company;
    }

    public Set<Address> getCurrentAddresses()
    {
        return currentAddresses;
    }

    public void setCurrentAddresses(Set<Address> currentAddresses)
    {
        this.currentAddresses = currentAddresses;
    }

    @Transient
    public boolean hasCurrentAddress(Address address)
    {
        return this.currentAddresses != null &&
            address != null &&
            this.currentAddresses.contains(address);
    }

    public java.util.Set<Role> getRoles()
    {
        return roles;
    }

    public void setRoles(java.util.Set<Role> roles)
    {
        this.roles = roles;
    }

    @Transient()
    public String getFullName()
    {
        String fullName = "";

        if (!JetUtils.isEmpty(firstName)) {
            fullName = firstName;
        }
        if (!JetUtils.isEmpty(middleName)) {
            if (!fullName.equals("")) {
                fullName = fullName.concat(" ");
            }
            fullName = fullName.concat(middleName);
        }
        if (!JetUtils.isEmpty(lastName)) {
            if (!fullName.equals("")) {
                fullName = fullName.concat(" ");
            }
            fullName = fullName.concat(lastName);
        }

        if (fullName.equals("")) {
            fullName = name;
        }

        return fullName;
    }

    ////////////////////////////////////////////////////
    // JetUser overrides
    ////////////////////////////////////////////////////

    @Transient()
    public boolean isAdmin()
    {
        for (Role role : roles) {
            if (role.getName().equals(Role.NAME_MEBS_ADMIN)) return true;
        }
        return false;
    }

    @Transient()
    public boolean isMebsUser()
    {
        for (Role role : roles) {
            if (role.isMebsRole()) return true;
        }
        return false;
    }

    @Transient()
    public boolean hasGlobalRole(Role role)
    {
        for (Role r : roles) {
            if (r.equals(role)) return true;
        }
        return false;
    }

    @Transient()
    public boolean hasRole(String roleName)
    {
        for (Role role : roles) {
            if (role.getName().equals(Role.NAME_MEBS_ADMIN)) return true;
            if (role.getName().equals(roleName)) return true;
        }
        return false;
    }


    @Transient()
    public boolean hasExclusiveRole(String roleName)
    {
         return hasRole(roleName) && !hasRole(Role.NAME_MEBS_ADMIN);
    }

    @Transient()
    public boolean hasGlobalRoles(String [] rolesNames)
    {
        for(String roleName : rolesNames){
            for (Role r : roles) {
                if (r.getName().equals(roleName)) return true;
            }
        }
        return false;
    }

    @Transient()
    public boolean hasCommonReadOnlyAccess()
    {
        for (Role r : roles) {
            if (r.getName().equals(Role.NAME_MEBS_ADMIN)) return true;
            if (r.hasCommonReadOnlyAccess()) return true;
        }
        return false;
    }

    @Transient
    public String getStatusString()
    {
        return status == null ? "" : Status.getByStatus(status).getObjectName(); 
    }

    ////////////////////////////////////////////////////
    // JetNamedObject overrides
    ////////////////////////////////////////////////////

    @Transient()
    public Object getObjectId()
    {
        return getId();
    }

    @Transient()
    public String getObjectName()
    {
        return getFullName();
    }

    public enum Status implements JetNamedObject {
        active(1),
        inactive(2),
        deleted(3);

        public final int status;

        Status(int status)
        {
            this.status = status;
        }

        public Object getObjectId()
        {
            return status;
        }

        public String getObjectName()
        {
            return name();
        }

        public int getStatus()
        {
            return status;
        }

        public static Status getByStatus(int id)
        {
            for (Status status : Status.values()) {
                if (status.getStatus() == id) {
                    return status;
                }
            }
            return null;
        }
    }

    @Override
    public String toString()
    {
        return this.getFullName();
    }

    public static void main(String[] args)
    {
        System.out.println("p=" + JetSecurityUtils.makeDigest("admin", "admin"));
    }

    @Transient()
    public static String[] getClientReadOnly() {
        return Role.ClientReadOnly;
    }

    @Transient()
    public static String[] getUsersReadOnly() {
        return Role.UsersReadOnly;
    }

    @Transient()
    public static String[] getClientReadAccess() {
        return Role.ClientReadAccess;
    }


    @Transient()
    public static String[] getUsersReadAccess() {
        return Role.UsersReadAccess;
    }

    @Transient()
    public static String[] getUsersFullAccess() {
        return Role.UsersFullAccess;
    }

    @Transient()
    public static String[] getReportsFullAccess() {
        return Role.ReportsFullAccess;
    }

    @Transient()
    public static String[] getReportsReadAccess() {
        return Role.ReportsReadAccess;
    }

    @Transient()
    public static String[] getAgentsFullAccess() {
        return Role.AgentsFullAccess;
    }

    @Transient()
    public static String[] getClientFullAccess() {
        return Role.ClientFullAccess;
    }

    @Transient()
    public static String[] getLogisticsFullAccess() {
        return Role.LogisticsFullAccess;
    }

    @Transient()
    public static String[] getLogisticsReadAccess() {
        return Role.LogisticsReadAccess;
    }

    @Transient()
    public boolean hasTabAccess(String tabName) {
        String [] accessRoles = Role.tabAccess.get(tabName);
        if(accessRoles == null)
            return true;
        else
            return this.hasGlobalRoles(accessRoles);

    }

}
